package agile.tools.autotest.runner;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import org.junit.Assert;

import agile.tools.autotest.MethodRecord;
import agile.tools.autotest.MethodRecorder;
import agile.tools.autotest.matcher.Matcher;

public class RecordedTestRunner implements IRecordedTestRunner {
	
	@SuppressWarnings("unchecked")
	public void runTest() {
		try {
			MethodRecorder recorder = MethodRecorder.defaultMethodRecorder();
			MethodRecord record = recorder.getSingleTestDataSet(dataSetName());
			Class[] inputParamClasses = (Class[]) recorder.deserializedInputParamsTypesNullIfEmpty();
			Object objectUnderTest = getObjectUnderTest(record.objectUnderTest());
			Method method = objectUnderTest.getClass().getMethod(record.methodName(), inputParamClasses);

			Object returnValue = method.invoke(objectUnderTest, recorder.deserializedInputParams().toArray());
			Object expectedValue = recorder.deserializedExpectedReturn();
			
			verifyExpectedAndActualResults(expectedValue, returnValue);
		} catch (IllegalArgumentException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (SecurityException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (NoSuchMethodException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	public Object getObjectUnderTest(String name) {
		try {
			return Class.forName(name).newInstance();
		} catch (InstantiationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return null;
	}

	@SuppressWarnings("unchecked")
	public void verifyExpectedAndActualResults(Object expected, Object actual) {
		if(expected != null) {
			String className = expected.getClass().getName();
			try {
				@SuppressWarnings("rawtypes")
				Matcher matcher = (Matcher) Class.forName(className + "Matcher").newInstance();
				matcher.match(expected, actual);
			} catch (ClassNotFoundException e) {
				Assert.assertEquals(expected, actual);
			}catch (InstantiationException e) {
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				e.printStackTrace();
			}
		} else {
			Assert.assertEquals(expected, actual);
		}
	}

	public String dataSetName() {
		return null;
	}
}